home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_08_09 / 8n09097a < prev    next >
Text File  |  1990-07-25  |  17KB  |  590 lines

  1. /*------------------------------------------------
  2. XMODEMR.C
  3.  
  4. Author      Date         Description
  5. -------------------------------------------
  6. Jon Ward  22 Apr 90  Initial Revision.
  7. Jon Ward  23 Apr 90  Cleanup and modify for
  8.                XMODEM-1K and XMODEM-CRC.
  9. Jon Ward  26 Apr 90  Corrected implementation
  10.                of XMODEM-CRC.
  11. Jon Ward  7 Jun 90   Added more comments and a
  12.                little cleanup.
  13. ------------------------------------------------*/
  14.  
  15. #define XMODEM_LIB 1
  16.  
  17. #include <stdio.h>
  18. #include "xmodem.h"
  19.  
  20.  
  21. #define STATIC static     /* undef for debugging */
  22.  
  23. /*------------------------------------------------
  24. ------------------------------------------------*/
  25. struct send_n_wait_st
  26.   {
  27.   char char_to_send;
  28.   int retry_count;
  29.   long ms_timeout;
  30.   unsigned char *valid_responses;
  31.   int num_valid_responses;
  32.   };
  33.  
  34. STATIC unsigned char soh_stx_can [] =
  35.   { SOH, STX, CAN };
  36. STATIC unsigned char soh_stx_can_eot [] =
  37.   { SOH, STX, CAN, EOT };
  38.  
  39. STATIC struct send_n_wait_st crc_req =
  40.   {
  41.   'C',
  42.   CRC_RETRY_COUNT,
  43.   CRC_TIMEOUT,
  44.   soh_stx_can,
  45.   sizeof (soh_stx_can)
  46.   };
  47.  
  48. STATIC struct send_n_wait_st checksum_req =
  49.   {
  50.   NAK,
  51.   NAK_RETRY_COUNT,
  52.   NAK_TIMEOUT,
  53.   soh_stx_can,
  54.   sizeof (soh_stx_can)
  55.   };
  56.  
  57. STATIC struct send_n_wait_st pack_nak =
  58.   {
  59.   NAK,
  60.   NAK_RETRY_COUNT,
  61.   NAK_TIMEOUT,
  62.   soh_stx_can_eot,
  63.   sizeof (soh_stx_can_eot)
  64.   };
  65.  
  66. STATIC struct send_n_wait_st pack_ack =
  67.   {
  68.   ACK,
  69.   ACK_RETRY_COUNT,
  70.   ACK_TIMEOUT,
  71.   soh_stx_can_eot,
  72.   sizeof (soh_stx_can_eot)
  73.   };
  74.  
  75.  
  76. /*------------------------------------------------
  77. Error messages for error enums.
  78. ------------------------------------------------*/
  79. STATIC char *xmodem_errors [] =
  80.   {
  81.   "Transmission Successful",
  82.   "NULL Transmit function pointer",
  83.   "NULL Receive function pointer",
  84.   "Receiver cancelled the transfer",
  85.   "Sender cancelled the transfer",
  86.   "User cancelled the transfer",
  87.   "Error reading the file",
  88.   "Error writing the file",
  89.   "Timed out waiting for data pack ACK",
  90.   "Timed out waiting for initial NAK",
  91.   "Timed out waiting for SOH",
  92.   "Timed out waiting for data",
  93.   "Timed out waiting for final ACK",
  94.   "Invalid char waiting for SOH",
  95.   "Block mismatch in packet header",
  96.   "CRC is incorrect",
  97.   "Checksum is incorrect",
  98.   "Block out of sequence",
  99.   "Received character error",
  100.   "Modem is not online",
  101.   };
  102.  
  103.  
  104. /*------------------------------------------------
  105.         Local Function Prototypes
  106. ------------------------------------------------*/
  107. STATIC int xm_send_n_wait (
  108.   const struct send_n_wait_st *req,    /* request structure */
  109.   unsigned char *response,        /* response from sender */
  110.   xfunc *xmf);                /* xmodem external functions */
  111.  
  112. STATIC int xm_block_start (
  113.   xblock *xb,            /* xmodem block data */
  114.   unsigned char block_start,    /* block start char from sender */
  115.   xfunc *xmf);            /* xmodem external functions */
  116.  
  117. STATIC int xm_recv_block (
  118.   xblock *xb,            /* xmodem block data */
  119.   register xfunc *xmf);        /* xmodem external functions */
  120.  
  121.  
  122. /*------------------------------------------------
  123. This function receives a file transferred via
  124. XMODEM, XMODEM-1K or XMODEM/CRC.  The f argument
  125. represents the file to receive that has been
  126. opened for writing.
  127. ------------------------------------------------*/
  128. int xmodem_recv (
  129.   FILE *f,                    /* file to write to */
  130.   int (*transmit) (char),            /* xmit function */
  131.   int (*receive) (long, unsigned int *),    /* recv function */
  132.   void (*dispstat) (long, long, const char *),    /* display function */
  133.   int (*check_abort) (void))            /* manual abort function */
  134. {
  135. register int error;      /* gen purpose error var */
  136. unsigned char start_char; /* first char of block */
  137. unsigned char next_block; /* next block we expect */
  138. unsigned char last_block; /* last successful block */
  139. xblock xb;          /* xmodem block data */
  140. xfunc xmfuncs;          /* xmodem external functions */
  141.  
  142.  
  143. /*------------------------------------------------
  144. Initialize the function pointer structure.
  145. ------------------------------------------------*/
  146. if ((xmfuncs.dispstat = dispstat) == NULL)
  147.   xmfuncs.dispstat = xm_no_disp_func;
  148.  
  149. if ((xmfuncs.check_abort = check_abort) == NULL)
  150.   xmfuncs.check_abort = xm_no_abort_func;
  151.  
  152. if ((xmfuncs.transmit = transmit) == NULL)
  153.   return (xm_perror (XERR_XMIT_FUNC, &xmfuncs));
  154.  
  155. if ((xmfuncs.receive = receive) == NULL)
  156.   return (xm_perror (XERR_RCVR_FUNC, &xmfuncs));
  157.  
  158.  
  159. /*------------------------------------------------
  160. Initialize data for the first block and purge
  161. all data from the receive buffer.  Init the 
  162. number of bytes and blocks received and display
  163. some useful info.
  164. ------------------------------------------------*/
  165. next_block = last_block = 1;
  166.  
  167. xb.total_block_count = 0L;
  168. xb.total_byte_count = 0L;
  169.  
  170. (*xmfuncs.dispstat) (0L, 0L, "");
  171.  
  172. PURGE_RECEIVER(receive);
  173.  
  174.  
  175. /*------------------------------------------------
  176. Attempt to transfer using CRC-16 error detection.
  177. This involves sending the CRC begin character:
  178. 'C'.
  179. ------------------------------------------------*/
  180. xb.crc_used = 1;
  181. error = xm_send_n_wait (&crc_req,
  182.             &start_char,
  183.             &xmfuncs);
  184.  
  185.  
  186. /*------------------------------------------------
  187. If the sender did not respond to the CRC-16
  188. transfer request, then attempt to transfer using
  189. checksum error detection.
  190. ------------------------------------------------*/
  191. if (error == XERR_SOH_TIMEOUT)
  192.   {
  193.   xb.crc_used = 0;
  194.   error = xm_send_n_wait (&checksum_req,
  195.               &start_char,
  196.               &xmfuncs);
  197.   }
  198.  
  199.  
  200. /*------------------------------------------------
  201. If begin transfer request failed, return error.
  202. ------------------------------------------------*/
  203. if (error != XERR_OK)
  204.   return (error);
  205.  
  206.  
  207. /*------------------------------------------------
  208. If the starting character of the next block is
  209. an EOT, then we have completed transferring the
  210. file and we exit this loop.  Otherwise, we init
  211. the xmodem packet structure based on the first
  212. character of the packet.
  213. ------------------------------------------------*/
  214. while (start_char != EOT)
  215.   {
  216.   register int good_block;    /* NZ if packet was OK */
  217.  
  218.   error = xm_block_start (&xb,
  219.               start_char,
  220.               &xmfuncs);
  221.  
  222.   if (error != XERR_OK)
  223.     return (error);
  224.  
  225.   good_block = -1;        /* assume packet will be OK */
  226.  
  227.  
  228. /*------------------------------------------------
  229. Receive the packet.  If there was an error, then
  230. NAK it.  Otherwise, the packet was received OK.
  231. ------------------------------------------------*/
  232.   if (xm_recv_block (&xb, &xmfuncs) != XERR_OK)
  233.     {
  234.     good_block = 0;            /* bad block */
  235.     }
  236.  
  237. /*------------------------------------------------
  238. If this is the next expected packet, then append
  239. it to the file and update the last and next
  240. packet vars.
  241. ------------------------------------------------*/
  242.   else if (xb.block_num == next_block)
  243.     {
  244.     int bytes_written;    /* bytes written for this block */
  245.  
  246.     last_block = next_block;
  247.     next_block = (next_block + 1) % 256;
  248.  
  249.     bytes_written = fwrite (xb.buffer, 1, xb.buflen, f);
  250.  
  251.     xb.total_block_count++;
  252.     xb.total_byte_count += bytes_written;
  253.  
  254.     (*xmfuncs.dispstat) (xb.total_block_count,
  255.              xb.total_byte_count,
  256.              NULL);
  257.  
  258.     if (bytes_written != xb.buflen)
  259.       {
  260.       xm_send_cancel (transmit);
  261.       return (xm_perror (XERR_FILE_WRITE, &xmfuncs));
  262.       }
  263.     }
  264.  
  265.  
  266. /*------------------------------------------------
  267. If this is the previous packet, then the sender
  268. did not receive our ACK to that packet and
  269. resent it.  This is OK.  Just ACK the packet.
  270.  
  271. If the block number for this packet is completely
  272. out of sequence, cancel the transmission and
  273. return an error.
  274. ------------------------------------------------*/
  275.   else if (xb.block_num != last_block)
  276.     {
  277.     xm_send_cancel (transmit);
  278.     return (xm_perror (XERR_BLOCK_SEQUENCE, &xmfuncs));
  279.     }
  280.  
  281.  
  282. /*------------------------------------------------
  283. Here, good_block is non-zero if the block was
  284. received and processed with no problems.  If it
  285. was a good block, then we send an ACK.  A NAK is
  286. sent for bad blocks.
  287. ------------------------------------------------*/
  288.   if (